package com.atguigu.juc.chap02;

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

/**
 * @author Taeyang
 * @date 2025/3/31
 */
public class LockDowngradingDemo02 {

    /**
     * 读写锁
     */
    private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock();

    /**
     * 读锁
     */
    private final Lock readLock = lock.readLock();

    /**
     * 写锁
     */
    private final Lock writeLock = lock.writeLock();

    private Integer data = 0;

    public static void main(String[] args) {
        LockDowngradingDemo02 demo = new LockDowngradingDemo02();

        new Thread(() -> {
            demo.updateDate(999);
        }, "更新线程01").start();

        new Thread(() -> {
            demo.updateDate(666);
        }, "更新线程02").start();

        new Thread(() -> {
            demo.readDate();
        }, "读线程01").start();

        new Thread(() -> {
            demo.readDate();
        }, "读线程02").start();
    }

    /**
     * 读数据
     *
     * @return 数据
     */
    public Integer readDate() {
        readLock.lock();

        System.out.println("读数据begin " + Thread.currentThread().getName());

        try {
            Thread.sleep(500);
            return data;
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        } finally {
            System.out.println("读数据end " + Thread.currentThread().getName() + " " + data);
            readLock.unlock();
        }
    }

    public Integer updateDate(int newValue) {

        writeLock.lock();
        System.out.println("更新数据begin " + Thread.currentThread().getName() + " " + newValue);
        try {
            Thread.sleep(500);
            data = newValue;
            // 锁降级（锁的可重入）
            readLock.lock();
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        } finally {
            System.out.println("更新数据end " + Thread.currentThread().getName() + " " + newValue);
            writeLock.unlock();
        }

        try {
            return readDate();
        } finally {
            System.out.println("释放读锁 " + Thread.currentThread().getName());
            readLock.unlock();
        }
    }

}
